/*
 * Copyright 2008 Karel Klic.
 * This file is part of Oslavanský Bot.
 * 
 * Oslavanský Bot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package categorybot;

import java.net.*;
import java.util.*;
import java.io.*;
import org.apache.commons.cli.*;
import net.sourceforge.jwbf.actions.http.*;
import net.sourceforge.jwbf.contentRep.mw.*;
import org.apache.commons.lang.math.*;
import org.apache.log4j.*;

public class Main {

  static List<Language> languageList = LanguageFactory.createLanguageList();
  static int wordCounter = 0;
  static WikiService service;

  static boolean solveWord(ContentAccessable content, boolean commit)
          throws ActionException, ProcessException {
    String originalText = content.getText();
    ArrayList<SolveCategoryResult> result = new ArrayList<SolveCategoryResult>();
    for (Language l : languageList) {
      result.addAll(l.solveWord(originalText));
    }

    if (result.size() == 0) {
      return false;
    }
    
    String changedText = originalText;
    
    // Apply changes.
    for (SolveCategoryResult request : result) {
      switch (request.getChangeType()) {
        case Add:
          changedText = CategoryAppender.appendCategory(changedText, request.getCategoryId());
          break;
        case Remove:
          changedText = CategoryRemover.removeCategory(changedText, request.getCategoryId());
          break;
      }
    }

    if (commit) {
      SimpleArticle article = new SimpleArticle(content);
      article.setText(changedText);
      article.setMinorEdit(true);
      article.setEditSummary(new EditorSummaryBuilder(result).toString());
      service.writeContent(article);
    } else {
      // Store the new file.
      try {
        OutputStream fstream = new FileOutputStream("file" + wordCounter + ".txt", true);
        OutputStreamWriter out = new OutputStreamWriter(fstream, "UTF-8");
        out.write(originalText);
        out.write("\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n\n");
        out.write(changedText);
        out.close();
      } catch (Exception e) {//Catch exception if any
        System.err.println("Error: " + e.getMessage());
      }
    }

    ++wordCounter;

    return true;
  }

  static void process(int wordLimit, boolean commit) 
          throws ActionException, ProcessException {
    Iterator<String> iterator = service.getIterator();

    ArrayList<String> problematicWordList = new ArrayList<String>();
    for (int i = 0; i < wordLimit; ++i) {      
      if (!iterator.hasNext()) {
        break;
      }
      String pageName = iterator.next();
      
      if (i == 0) {
        System.out.println();
        System.out.println("First word: " + pageName);
      }
      if (i == wordLimit - 1 || !iterator.hasNext()) {
        System.out.println();
        System.out.println("Last word: " + pageName);
      }
      
      try {
        Thread.sleep(4000);
      } catch (InterruptedException ex) {
      }
      ContentAccessable content = service.readContent(pageName);
      boolean problem = solveWord(content, commit);
      if (problem) {
        System.out.println();
        System.out.println(pageName);
        problematicWordList.add(pageName);
      } else {
        System.out.print(".");
      }
    }

    System.out.println();
    System.out.println("List of all problematic words:");
    for (String word : problematicWordList) {
      System.out.print(word + ", ");
    }
  }

  /**
   * Entry function.
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    // Set up a simple configuration that logs on the console.
    PropertyConfigurator.configure("log4j.properties");

    Settings settings = new Settings();
    try {
      CommandLine commandLine = settings.parse(args);
      if (commandLine.hasOption("help")) {
        settings.showHelp();
        return;
      }

      String userName = commandLine.getOptionValue("username");
      String password = commandLine.getOptionValue("password");
      service = new WikiService(userName, password);

      if (commandLine.hasOption("prefix")) {
        service.setPrefix(commandLine.getOptionValue("prefix"));
      } 
      
      if (commandLine.hasOption("from")) {
        service.setFrom(commandLine.getOptionValue("from"));
      }
      
      int wordLimit = 100;
      if (commandLine.hasOption("limit"))
        wordLimit = NumberUtils.createInteger(commandLine.getOptionValue("limit"));
      
      process(wordLimit, commandLine.hasOption("commit"));
    } catch (ParseException ex) {
      System.err.println("Parsing failed. Reason: " + ex.getMessage());
      settings.showHelp();
    } catch (NumberFormatException ex) {
      System.err.println("Number parsing failed. Reason: " + ex.getMessage());
      settings.showHelp();
    } catch (MalformedURLException ex) {
      System.err.println("Invalid URL. Details: " + ex.getMessage());
    } catch (ActionException ex) {
      System.err.println("Bot action failed. Reason: " + ex.getMessage());
    } catch (ProcessException ex) {
      System.err.println("Word process failed. Reason: " + ex.getMessage());
    }
  }
}
